package top.baselitch.liteorm;

import android.content.ContentValues;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;

import top.baselitch.liteorm.annotation.DBInsert;
import top.baselitch.liteorm.annotation.DBQuery;
import top.baselitch.liteorm.annotation.QueryColumns;
import top.baselitch.liteorm.annotation.Table;
import top.baselitch.liteorm.annotation.TableField;
import top.baselitch.liteorm.annotation.TableFields;

public class DaoMethod {
    public static final int ACTION_INSERT = 0x01;
    public static final int ACTION_DELETE = 0x02;
    public static final int ACTION_UPDATE = 0x03;
    public static final int ACTION_QUERY = 0x04;
    private int daoAction;//Dao操作标识
    private String tableName;//表名
    private String[] queryColumnts;//查询字段名数组
    private String querySelection;//查询条件语句
    private ContentValues contentValues;
    private String[] selectionArgs;
    private DaoExecutor<?> daoExecutor;
    private DaoMethod(Builder builder){
        this.daoAction = builder.daoAction;
        this.tableName = builder.tableName;
        this.contentValues = builder.contentValues;
        this.queryColumnts = builder.queryColumns;
        this.querySelection = builder.selection;
        this.selectionArgs = builder.selectionArgs;
    }
    public static class Builder{
        private int daoAction;
        private Method daoMethod;
        private Annotation[] methodAnnotations;//方法注解数组
        private Annotation[][] parameterAnnotations;//参数注解二维数组
        private Class[] parameteTypes;//参数类型
        private Object[] args;//参数对象数组
        private String tableName;//表名
        private String tableFiledName;//表字段名数组
        private ContentValues contentValues;
        private String[] queryColumns;//查询字段数组
        private String selection;//查询条件
        private String[] selectionArgs;//查询条件值
        private StringBuilder selectionBuilder;
        private class MethodException extends RuntimeException{
            public MethodException(String detailMessage) {
                super(detailMessage);
            }
        }
        public Builder(Method daoMethod,Object[] args){
            this.daoMethod = daoMethod;
            this.methodAnnotations = daoMethod.getAnnotations();
            this.parameterAnnotations = daoMethod.getParameterAnnotations();
            this.parameteTypes = daoMethod.getParameterTypes();
            this.args = args;
        }
        public DaoMethod builder(){
            for(Annotation annotation : methodAnnotations){
                parseMethodAnnotation(annotation);
            }
            return new DaoMethod(this);
        }

        /**
         * 解析方法上的注解类
         * @param annotation 注解类对象
         */
        private void parseMethodAnnotation(Annotation annotation){
            if(annotation instanceof DBInsert){
                parseDaoActionAndTableModel(DaoMethod.ACTION_INSERT,((DBInsert) annotation).tableMode());
            }else if(annotation instanceof DBQuery){
                parseDaoActionAndTableModel(DaoMethod.ACTION_QUERY,((DBQuery) annotation).tableMode());
            }else if(annotation instanceof QueryColumns){
                this.queryColumns = ((QueryColumns) annotation).clumns();
            }
        }

        /**
         * 解析实例对象的Table
         */
        private <T> void parseDaoActionAndTableModel(int action,Class<T> tableModel){
            Tables.addTable(tableModel);
            Table table = tableModel.getAnnotation(Table.class);
            tableName = table.value();
            daoAction = action;
            if(action == ACTION_INSERT){//插入操作
                contentValues = new ContentValues();
                for(int i=0;i<parameterAnnotations.length;i++){
                    Class typeClass = parameteTypes[i];
                    Object arg = args[i];
                    for(int p = 0;p<parameterAnnotations[i].length;p++){
                        parseParameteAnnotation(parameterAnnotations[i][p],typeClass,arg);
                    }
                }
            }else if(action == ACTION_QUERY){//查询操作
                selectionBuilder = new StringBuilder();
                selectionArgs = new String[parameterAnnotations.length];
                for(int i=0;i<parameterAnnotations.length;i++){
                    Class typeClass = parameteTypes[i];
                    Object arg = args[i];
                    for(int p = 0;p<parameterAnnotations[i].length;p++){
                        parseQueryAnnotation(parameterAnnotations[i][p],i==parameterAnnotations.length-1,typeClass,arg,i);
                    }
                }
            }
        }

        /**
         * 解析参数上的注解
         * @param annotation 注解对象
         */
        private void parseParameteAnnotation(Annotation annotation,Class typeClass,Object arg){
            if(annotation instanceof TableFields){//Table对象
                if(!typeClass.isAnnotationPresent(Table.class)){
                    throw new MethodException("Dao Method paramete has 'TableFields' annotation, but paramete target is not Table");
                }
                try {
                    parseTableFields(typeClass,arg);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }else if(annotation instanceof TableField){
                parseTableFieldsAnnotation(((TableField) annotation).value(),typeClass,arg);
            }
        }

        /**
         * 解析表对象
         * @param typeClass 方法参数类型
         * @param arg 方法参数对象
         * @throws IllegalAccessException
         */
        private void parseTableFields(Class typeClass,Object arg) throws IllegalAccessException {
            Field[] fields = typeClass.getDeclaredFields();
            for(Field field : fields){
                if(field.isAnnotationPresent(TableField.class)){
                    field.setAccessible(true);
                    TableField tableField = field.getAnnotation(TableField.class);
                    String fieldType = field.getType().getName();
                    if(fieldType.equals("int")){
                        contentValues.put(tableField.value(),field.getInt(arg));
                    }else if(fieldType.equals("java.lang.String")){
                        contentValues.put(tableField.value(),String.valueOf(field.get(arg)));
                    }else if(fieldType.equals("long")){
                        contentValues.put(tableField.value(),field.getLong(arg));
                    }else if(fieldType.equals("boolean")){
                        contentValues.put(tableField.value(),field.getBoolean(arg));
                    }
                }
            }
        }

        /**
         * 解析表字段
         * @param fieldName 字段名
         * @param typeClass
         * @param arg
         */
        private void parseTableFieldsAnnotation(String fieldName,Class typeClass,Object arg){
            String fieldType = typeClass.getName();
            if(fieldType.equals("int")){
                contentValues.put(fieldName,Integer.parseInt(String.valueOf(arg)));
            }else if(fieldType.equals("java.lang.String")){
                contentValues.put(fieldName,String.valueOf(arg));
            }else if(fieldType.equals("long")){
                contentValues.put(fieldName,Long.parseLong(String.valueOf(arg)));
            }else if(fieldType.equals("boolean")){
                contentValues.put(fieldName,Boolean.parseBoolean(String.valueOf(arg)));
            }
        }

        /**
         * 解析查询条件注解
         */
        private void parseQueryAnnotation(Annotation annotation,boolean isEnd,Class typeClass,Object arg,int index){
            if(annotation instanceof TableField){
                selectionBuilder.append(((TableField) annotation).value() + "=?");
                selectionBuilder.append(isEnd?"":",");
                if(typeClass.getName().equals("java.lang.String")){
                    selectionArgs[index] = "'" + String.valueOf(arg) + "'";
                }else{
                    throw new MethodException("this method is a query can only add String parameter");
                }
            }
            if(isEnd){
                selection = selectionBuilder.toString();
            }
        }
    }


    public int getDaoAction() {
        return daoAction;
    }

    public String getTableName() {
        return tableName;
    }

    public String[] getQueryColumnts() {
        return queryColumnts;
    }

    public ContentValues getInserDatas() {
        return contentValues;
    }


    public String getQuerySelection() {
        return querySelection;
    }

    public String[] getSelectionArgs() {
        return selectionArgs;
    }
}
